[XEN][HVM] Make sure that the interrupt which event channel events come in
authorSteven Smith <ssmith@xensource.com>
Fri, 29 Sep 2006 13:42:04 +0000 (14:42 +0100)
committerSteven Smith <ssmith@xensource.com>
Fri, 29 Sep 2006 13:42:04 +0000 (14:42 +0100)
on is level triggered rather than edge triggered, since it's a PCI device.
This is complicated by the possibility that another PCI device could be
on the same interrupt; the workaround is to have two irr registers
for the PIC and APIC, and have qemu and Xen generated interrupts go
into different ones.

This broke the alt_irq stuff.  Fortunately, nobody uses that anymore, so
I've removed it.

Signed-off-by: Steven Smith <sos22@cam.ac.uk>
xen/arch/x86/hvm/i8259.c
xen/arch/x86/hvm/svm/intr.c
xen/arch/x86/hvm/vioapic.c
xen/arch/x86/hvm/vmx/io.c
xen/include/asm-x86/hvm/vioapic.h
xen/include/asm-x86/hvm/vpic.h

index 4e29cbfa854807c3c531ce3b7a78e173cb7e7332..e90f3650442bef4516ca713537cff2d8e7a3069d 100644 (file)
@@ -86,7 +86,7 @@ static int pic_get_irq(PicState *s)
 
     ASSERT(spin_is_locked(&s->pics_state->lock));
 
-    mask = s->irr & ~s->imr;
+    mask = (s->irr|s->irr_xen) & ~s->imr;
     priority = get_priority(s, mask);
     if (priority == 8)
         return -1;
@@ -128,6 +128,32 @@ void pic_update_irq(struct hvm_virpic *s)
     }
 }
 
+void pic_set_xen_irq(void *opaque, int irq, int level)
+{
+    struct hvm_virpic *s = opaque;
+    unsigned long flags;
+    PicState *ps;
+
+    spin_lock_irqsave(&s->lock, flags);
+
+    hvm_vioapic_set_xen_irq(current->domain, irq, level);
+
+    /* Set it on the 8259s */
+    ps = &s->pics[irq >> 3];
+    if (!(ps->elcr & (1 << (irq & 7)))) {
+       DPRINTK("edge-triggered override IRQ?\n");
+       domain_crash(current->domain);
+    }
+    if (level) {
+       ps->irr_xen |= 1 << (irq & 7);
+    } else {
+       ps->irr_xen &= ~(1 << (irq & 7));
+    }
+
+    pic_update_irq(s);
+    spin_unlock_irqrestore(&s->lock, flags);
+}
+
 void pic_set_irq_new(void *opaque, int irq, int level)
 {
     struct hvm_virpic *s = opaque;
@@ -136,9 +162,6 @@ void pic_set_irq_new(void *opaque, int irq, int level)
     spin_lock_irqsave(&s->lock, flags);
     hvm_vioapic_set_irq(current->domain, irq, level);
     pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
-    /* used for IOAPIC irqs */
-    if (s->alt_irq_func)
-        s->alt_irq_func(s->alt_irq_opaque, irq, level);
     pic_update_irq(s);
     spin_unlock_irqrestore(&s->lock, flags);
 }
@@ -371,6 +394,7 @@ static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
             s->pics_state->pics[0].irr &= ~(1 << 2);
         }
         s->irr &= ~(1 << ret);
+        s->irr_xen &= ~(1 << ret);
         s->isr &= ~(1 << ret);
         if (addr1 >> 7 || ret != 2)
             pic_update_irq(s->pics_state);
@@ -400,7 +424,7 @@ static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
             if (s->read_reg_select)
                 ret = s->isr;
             else
-                ret = s->irr;
+                ret = s->irr | s->irr_xen;
         } else {
             ret = s->imr;
         }
@@ -472,18 +496,6 @@ void pic_init(struct hvm_virpic *s, void (*irq_request)(void *, int),
     s->irq_request_opaque = irq_request_opaque;
 }
 
-void pic_set_alt_irq_func(struct hvm_virpic *s,
-                          void (*alt_irq_func)(void *, int, int),
-                          void *alt_irq_opaque)
-{
-    unsigned long flags;
-
-    spin_lock_irqsave(&s->lock, flags);
-    s->alt_irq_func = alt_irq_func;
-    s->alt_irq_opaque = alt_irq_opaque;
-    spin_unlock_irqrestore(&s->lock, flags);
-}
-
 static int intercept_pic_io(ioreq_t *p)
 {
     struct hvm_virpic  *pic;
index d053c6d1226a51584de95a2c6176986cc15f9def..1e283d8bbefb494274f2bea413d31544c6bda408 100644 (file)
@@ -122,13 +122,8 @@ asmlinkage void svm_intr_assist(void)
       }
 
       callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
-      if ( callback_irq != 0 &&
-           local_events_need_delivery() ) {
-          /*inject para-device call back irq*/
-          v->vcpu_info->evtchn_upcall_mask = 1;
-          pic_set_irq(pic, callback_irq, 0);
-          pic_set_irq(pic, callback_irq, 1);
-      }
+      if ( callback_irq != 0)
+          pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
 
       if ( cpu_has_pending_irq(v) )
           intr_vector = cpu_get_interrupt(v, &intr_type);
index 2999bfe4f1f078329bf4b03ea4a2dbd563f01b98..daa812a6f39489c89f45f43f1145a55c9ff9e819 100644 (file)
@@ -479,7 +479,7 @@ static void ioapic_deliver(hvm_vioapic_t *s, int irqno)
 
 static int ioapic_get_highest_irq(hvm_vioapic_t *s)
 {
-    uint32_t irqs = s->irr & ~s->isr & ~s->imr;
+    uint32_t irqs = (s->irr | s->irr_xen) & ~s->isr & ~s->imr;
     return fls(irqs) - 1;
 }
 
@@ -501,6 +501,7 @@ static void service_ioapic(hvm_vioapic_t *s)
         }
 
         s->irr &= ~(1 << irqno);
+       s->irr_xen &= ~(1 << irqno);
     }
 }
 
@@ -526,6 +527,25 @@ void hvm_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs)
     service_ioapic(s);
 }
 
+void hvm_vioapic_set_xen_irq(struct domain *d, int irq, int level)
+{
+    hvm_vioapic_t *s = &d->arch.hvm_domain.vioapic;
+
+    if (!hvm_apic_support(d) || !IOAPICEnabled(s) ||
+       s->redirtbl[irq].RedirForm.mask)
+        return;
+
+    if (s->redirtbl[irq].RedirForm.trigmod != IOAPIC_LEVEL_TRIGGER) {
+       DPRINTK("Forcing edge triggered APIC irq %d?\n", irq);
+       domain_crash(d);
+    }
+
+    if (level)
+       s->irr_xen |= 1 << irq;
+    else
+       s->irr_xen &= ~(1 << irq);
+}
+
 void hvm_vioapic_set_irq(struct domain *d, int irq, int level)
 {
     hvm_vioapic_t *s = &(d->arch.hvm_domain.vioapic);
index 75632a41d6b984e78995d804de4bfc2a587664db..ae8d89a31d3bd77a8d21f4aafdfad4f00702fb9b 100644 (file)
@@ -92,13 +92,8 @@ asmlinkage void vmx_intr_assist(void)
     }
 
     callback_irq = v->domain->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ];
-    if ( callback_irq != 0 &&
-         local_events_need_delivery() ) {
-        /*inject para-device call back irq*/
-        v->vcpu_info->evtchn_upcall_mask = 1;
-        pic_set_irq(pic, callback_irq, 0);
-        pic_set_irq(pic, callback_irq, 1);
-    }
+    if ( callback_irq != 0 )
+        pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
 
     has_ext_irq = cpu_has_pending_irq(v);
 
index 72c758c1333b43b24467e52c7d57e9e62ddf6877..b5ec7e459792088aa3b6c1c41c1156ca46b7abbf 100644 (file)
@@ -88,6 +88,7 @@ typedef union RedirStatus
 
 typedef struct hvm_vioapic {
     uint32_t irr;
+    uint32_t irr_xen; /* interrupts forced on by the hypervisor. */
     uint32_t isr;           /* This is used for level trigger */
     uint32_t imr;
     uint32_t ioregsel;
@@ -105,6 +106,7 @@ hvm_vioapic_t *hvm_vioapic_init(struct domain *d);
 
 void hvm_vioapic_do_irqs_clear(struct domain *d, uint16_t irqs);
 void hvm_vioapic_do_irqs(struct domain *d, uint16_t irqs);
+void hvm_vioapic_set_xen_irq(struct domain *d, int irq, int level);
 void hvm_vioapic_set_irq(struct domain *d, int irq, int level);
 
 int hvm_vioapic_add_lapic(struct vlapic *vlapic, struct vcpu *v);
index 8fa5daa5ad8051d6b52d63487c3262e6ca8db28f..f6a488e339389d17bb7650fde89897775a7f51db 100644 (file)
@@ -34,6 +34,8 @@ typedef struct IOAPICState IOAPICState;
 typedef struct PicState {
     uint8_t last_irr; /* edge detection */
     uint8_t irr; /* interrupt request register */
+    uint8_t irr_xen; /* interrupts forced on by the hypervisor e.g.
+                       the callback irq. */
     uint8_t imr; /* interrupt mask register */
     uint8_t isr; /* interrupt service register */
     uint8_t priority_add; /* highest irq priority */
@@ -58,20 +60,16 @@ struct hvm_virpic {
     void (*irq_request)(void *opaque, int level);
     void *irq_request_opaque;
     /* IOAPIC callback support */
-    void (*alt_irq_func)(void *opaque, int irq_num, int level);
-    void *alt_irq_opaque;
     spinlock_t lock;
 };
 
 
+void pic_set_xen_irq(void *opaque, int irq, int level);
 void pic_set_irq(struct hvm_virpic *s, int irq, int level);
 void pic_set_irq_new(void *opaque, int irq, int level);
 void pic_init(struct hvm_virpic *s, 
               void (*irq_request)(void *, int),
               void *irq_request_opaque);
-void pic_set_alt_irq_func(struct hvm_virpic *s, 
-                          void (*alt_irq_func)(void *, int, int),
-                          void *alt_irq_opaque);
 int pic_read_irq(struct hvm_virpic *s);
 void pic_update_irq(struct hvm_virpic *s); /* Caller must hold s->lock */
 uint32_t pic_intack_read(struct hvm_virpic *s);